/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"nsInProcessTabChildGlobal.h"#include"nsContentUtils.h"#include"nsIScriptSecurityManager.h"#include"nsIInterfaceRequestorUtils.h"#include"nsIComponentManager.h"#include"nsIServiceManager.h"#include"nsComponentManagerUtils.h"#include"nsFrameLoader.h"#include"xpcpublic.h"#include"nsIMozBrowserFrame.h"#include"nsDOMClassInfoID.h"#include"mozilla/EventDispatcher.h"#include"mozilla/dom/SameProcessMessageQueue.h"#include"mozilla/dom/ScriptLoader.h"usingnamespacemozilla;usingnamespacemozilla::dom;usingnamespacemozilla::dom::ipc;boolnsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext*aCx,constnsAString&aMessage,StructuredCloneData&aData,JS::Handle<JSObject*>aCpows,nsIPrincipal*aPrincipal,nsTArray<StructuredCloneData>*aRetVal,boolaIsSync){SameProcessMessageQueue*queue=SameProcessMessageQueue::Get();queue->Flush();if(mChromeMessageManager){SameProcessCpowHoldercpows(JS::RootingContext::get(aCx),aCpows);RefPtr<nsFrameMessageManager>mm=mChromeMessageManager;nsCOMPtr<nsIFrameLoader>fl=GetFrameLoader();mm->ReceiveMessage(mOwner,fl,aMessage,true,&aData,&cpows,aPrincipal,aRetVal);}returntrue;}classnsAsyncMessageToParent:publicnsSameProcessAsyncMessageBase,publicSameProcessMessageQueue::Runnable{public:nsAsyncMessageToParent(JS::RootingContext*aRootingCx,JS::Handle<JSObject*>aCpows,nsInProcessTabChildGlobal*aTabChild):nsSameProcessAsyncMessageBase(aRootingCx,aCpows),mTabChild(aTabChild){}virtualnsresultHandleMessage()override{nsCOMPtr<nsIFrameLoader>fl=mTabChild->GetFrameLoader();ReceiveMessage(mTabChild->mOwner,fl,mTabChild->mChromeMessageManager);returnNS_OK;}RefPtr<nsInProcessTabChildGlobal>mTabChild;};nsresultnsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext*aCx,constnsAString&aMessage,StructuredCloneData&aData,JS::Handle<JSObject*>aCpows,nsIPrincipal*aPrincipal){SameProcessMessageQueue*queue=SameProcessMessageQueue::Get();JS::RootingContext*rcx=JS::RootingContext::get(aCx);RefPtr<nsAsyncMessageToParent>ev=newnsAsyncMessageToParent(rcx,aCpows,this);nsresultrv=ev->Init(aMessage,aData,aPrincipal);if(NS_FAILED(rv)){returnrv;}queue->Push(ev);returnNS_OK;}nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell*aShell,nsIContent*aOwner,nsFrameMessageManager*aChrome):mDocShell(aShell),mInitialized(false),mLoadingScript(false),mPreventEventsEscaping(false),mOwner(aOwner),mChromeMessageManager(aChrome){SetIsNotDOMBinding();mozilla::HoldJSObjects(this);// If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our// GetEventTargetParent implementation.nsCOMPtr<nsIMozBrowserFrame>browserFrame=do_QueryInterface(mOwner);if(browserFrame){mIsBrowserFrame=browserFrame->GetReallyIsBrowser();}else{mIsBrowserFrame=false;}}nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal(){mAnonymousGlobalScopes.Clear();mozilla::DropJSObjects(this);}// This method isn't automatically forwarded safely because it's notxpcom, so// the IDL binding doesn't know what value to return.NS_IMETHODIMP_(bool)nsInProcessTabChildGlobal::MarkForCC(){MarkScopesForCC();returnmMessageManager?mMessageManager->MarkForCC():false;}nsresultnsInProcessTabChildGlobal::Init(){#ifdef DEBUGnsresultrv=#endifInitTabChildGlobal();NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),"Couldn't initialize nsInProcessTabChildGlobal");mMessageManager=newnsFrameMessageManager(this,nullptr,dom::ipc::MM_CHILD);returnNS_OK;}NS_IMPL_CYCLE_COLLECTION_CLASS(nsInProcessTabChildGlobal)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsInProcessTabChildGlobal,DOMEventTargetHelper)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)tmp->TraverseHostObjectURIs(cb);NS_IMPL_CYCLE_COLLECTION_TRAVERSE_ENDNS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsInProcessTabChildGlobal,DOMEventTargetHelper)tmp->nsMessageManagerScriptExecutor::Trace(aCallbacks,aClosure);NS_IMPL_CYCLE_COLLECTION_TRACE_ENDNS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsInProcessTabChildGlobal,DOMEventTargetHelper)NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)tmp->nsMessageManagerScriptExecutor::Unlink();tmp->UnlinkHostObjectURIs();NS_IMPL_CYCLE_COLLECTION_UNLINK_ENDNS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)NS_INTERFACE_MAP_ENTRY(nsIMessageSender)NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)NS_INTERFACE_MAP_ENTRY(nsIContentFrameMessageManager)NS_INTERFACE_MAP_ENTRY(nsIInProcessContentFrameMessageManager)NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentFrameMessageManager)NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)NS_IMPL_ADDREF_INHERITED(nsInProcessTabChildGlobal,DOMEventTargetHelper)NS_IMPL_RELEASE_INHERITED(nsInProcessTabChildGlobal,DOMEventTargetHelper)voidnsInProcessTabChildGlobal::CacheFrameLoader(nsIFrameLoader*aFrameLoader){mFrameLoader=aFrameLoader;}NS_IMETHODIMPnsInProcessTabChildGlobal::GetContent(mozIDOMWindowProxy**aContent){*aContent=nullptr;if(!mDocShell){returnNS_OK;}nsCOMPtr<nsPIDOMWindowOuter>window=mDocShell->GetWindow();window.forget(aContent);returnNS_OK;}NS_IMETHODIMPnsInProcessTabChildGlobal::GetDocShell(nsIDocShell**aDocShell){NS_IF_ADDREF(*aDocShell=mDocShell);returnNS_OK;}voidnsInProcessTabChildGlobal::FireUnloadEvent(){// We're called from nsDocument::MaybeInitializeFinalizeFrameLoaders, so it// should be safe to run script.MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());// Don't let the unload event propagate to chrome event handlers.mPreventEventsEscaping=true;DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("unload"));// Allow events fired during docshell destruction (pagehide, unload) to// propagate to the <browser> element since chrome code depends on this.mPreventEventsEscaping=false;}voidnsInProcessTabChildGlobal::DisconnectEventListeners(){if(mDocShell){if(nsCOMPtr<nsPIDOMWindowOuter>win=mDocShell->GetWindow()){MOZ_ASSERT(win->IsOuterWindow());win->SetChromeEventHandler(win->GetChromeEventHandler());}}if(mListenerManager){mListenerManager->Disconnect();}mDocShell=nullptr;}voidnsInProcessTabChildGlobal::Disconnect(){mChromeMessageManager=nullptr;mOwner=nullptr;if(mMessageManager){static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();mMessageManager=nullptr;}}NS_IMETHODIMP_(nsIContent*)nsInProcessTabChildGlobal::GetOwnerContent(){returnmOwner;}nsresultnsInProcessTabChildGlobal::GetEventTargetParent(EventChainPreVisitor&aVisitor){aVisitor.mForceContentDispatch=true;aVisitor.mCanHandle=true;#ifdef DEBUGif(mOwner){nsCOMPtr<nsIFrameLoaderOwner>owner=do_QueryInterface(mOwner);RefPtr<nsFrameLoader>fl=owner->GetFrameLoader();if(fl){NS_ASSERTION(this==fl->GetTabChildGlobalAsEventTarget(),"Wrong event target!");NS_ASSERTION(fl->mMessageManager==mChromeMessageManager,"Wrong message manager!");}}#endifif(mPreventEventsEscaping){aVisitor.mParentTarget=nullptr;returnNS_OK;}if(mIsBrowserFrame&&(!mOwner||!nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))){if(mOwner){if(nsPIDOMWindowInner*innerWindow=mOwner->OwnerDoc()->GetInnerWindow()){aVisitor.mParentTarget=innerWindow->GetParentTarget();}}}else{aVisitor.mParentTarget=mOwner;}returnNS_OK;}nsresultnsInProcessTabChildGlobal::InitTabChildGlobal(){// If you change this, please change GetCompartmentName() in XPCJSContext.cpp// accordingly.nsAutoCStringid;id.AssignLiteral("inProcessTabChildGlobal");nsIURI*uri=mOwner->OwnerDoc()->GetDocumentURI();if(uri){nsAutoCStringu;nsresultrv=uri->GetSpec(u);NS_ENSURE_SUCCESS(rv,rv);id.AppendLiteral("?ownedBy=");id.Append(u);}nsISupports*scopeSupports=NS_ISUPPORTS_CAST(EventTarget*,this);NS_ENSURE_STATE(InitChildGlobalInternal(scopeSupports,id));returnNS_OK;}classnsAsyncScriptLoad:publicRunnable{public:nsAsyncScriptLoad(nsInProcessTabChildGlobal*aTabChild,constnsAString&aURL,boolaRunInGlobalScope):mozilla::Runnable("nsAsyncScriptLoad"),mTabChild(aTabChild),mURL(aURL),mRunInGlobalScope(aRunInGlobalScope){}NS_IMETHODRun()override{mTabChild->LoadFrameScript(mURL,mRunInGlobalScope);returnNS_OK;}RefPtr<nsInProcessTabChildGlobal>mTabChild;nsStringmURL;boolmRunInGlobalScope;};voidnsInProcessTabChildGlobal::LoadFrameScript(constnsAString&aURL,boolaRunInGlobalScope){if(!nsContentUtils::IsSafeToRunScript()){nsContentUtils::AddScriptRunner(newnsAsyncScriptLoad(this,aURL,aRunInGlobalScope));return;}if(!mInitialized){mInitialized=true;Init();}booltmp=mLoadingScript;mLoadingScript=true;LoadScriptInternal(aURL,aRunInGlobalScope);mLoadingScript=tmp;}already_AddRefed<nsIFrameLoader>nsInProcessTabChildGlobal::GetFrameLoader(){nsCOMPtr<nsIFrameLoaderOwner>owner=do_QueryInterface(mOwner);nsCOMPtr<nsIFrameLoader>fl=owner?owner->GetFrameLoader():nullptr;if(!fl){fl=mFrameLoader;}returnfl.forget();}